<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2020/12/18
 * Time: 15:40
 */
namespace app\web\util;

use app\web\model\Shop;
use think\facade\Db;

class AlibabaUtil{
    private $_app_key;
    private $_app_secret;
    private $_redirect_url;
    private $_site_url;
    private $_version = 1;
    private $_web_site = '1688';

    /**
     * @todo 初始化构造方法
     */
    public function __construct()
    {
        $this->_app_key = config('alibaba.app_key');
        $this->_app_secret = config('alibaba.app_secret');
        $this->_redirect_url = config('alibaba.redirect_url');
        $this->_site_url = config('alibaba.site_url');
    }

    /**
     * @todo 生成授权链接
     * @author ZJF
     * https://open.1688.com/api/apidoclist.htm?id=624396
     */
    public function createAuthUrl($state=''){
        $redirect_url = "https://quickprint.xingyebao.com/login/login";
        $param = array(
            'client_id' => $this->_app_key,
            'site' => $this->_web_site,
            'redirect_uri'=>$redirect_url,//$this->_redirect_url
        );
        if(!empty($state)){
            $param['state'] = $state;
        }
        $url = "https://auth.1688.com/oauth/authorize?".http_build_query($param);
        return $url;
    }

    /**
     * @todo 通过code获取令牌
     * @author ZJF
     * https://open.1688.com/api/apidoclist.htm?id=624396
     */
    public function creatAccessToken($code = '',$redirect_uri = ''){
        $api_url = "/http/1/system.oauth2/getToken/{$this->_app_key}";
        $_param = array(
            'grant_type' => 'authorization_code',
            'need_refresh_token' => 'true',
            'client_id' => $this->_app_key,
            'client_secret' => $this->_app_secret,
            'redirect_uri' => empty($redirect_uri)?$_SERVER['HTTP_HOST']:$redirect_uri,
            'code' => $code
        );
        $response = HttpRequest($this->_site_url.$api_url,[],$_param,'POST');
        $response = json_decode($response,1);
        if(empty($response['aliId'])){
            // 授权获取失败
            return array_response($response, 1,'获取授权失败');
        }
        return array_response($response);
    }

    /**
     * @todo 刷新accessToken
     * @author ZJF
     */
    public function refreshAccessToken($refresh_token = ''){
        $api_url = '/param2/1/system.oauth2/getToken/'.$this->_app_key;
        $_param = array(
            'grant_type' => 'refresh_token',
            'client_id' => $this->_app_key,
            'client_secret' => $this->_app_secret,
            'refresh_token' => $refresh_token
        );
        $response = HttpRequest($this->_site_url.$api_url,[],$_param,'POST');
        $response = json_decode($response,1);
        if(empty($response['access_token'])){
            // 授权获取失败
            return array_response($response, 1,'刷新授权失败');
        }
        return array_response($response);
    }

    /**
     * @todo 订单列表查看(卖家视角)
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.getSellerOrderList-1&aopApiCategory=trade_new
     */
    public function getSellerOrderList($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.getSellerOrderList';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'page'=>empty($param['page'])?1:$param['page'],
            'pageSize'=>empty($param['pageSize'])?20:$param['pageSize'],
        );
        //下单开始时间
        if(!empty($param['createStartTime'])){
            $_param['createStartTime'] = $param['createStartTime'];
        }
        //下单结束时间
        if(!empty($param['createEndTime'])){
            $_param['createEndTime'] = $param['createEndTime'];
        }
        //查询修改时间开始
        if(!empty($param['modifyStartTime'])){
            $_param['modifyStartTime'] = $param['modifyStartTime'];
        }
        //查询修改时间结束
        if(!empty($param['modifyEndTime'])){
            $_param['modifyEndTime'] = $param['modifyEndTime'];
        }
        //订单状态，
        //值有success,cancel(交易取消，违约金等交割完毕),
        //waitbuyerpay(等待买家付款)，
        //waitsellersend(等待卖家发货),
        //waitbuyerreceive(等待买家收货)
        if(!empty($param['orderStatus'])){
            $_param['orderStatus'] = $param['orderStatus'];
        }
        //退款状态，
        //支持： "waitselleragree"(等待卖家同意),
        // "refundsuccess"(退款成功),
        // "refundclose"(退款关闭),
        // "waitbuyermodify"(待买家修改),
        // "waitbuyersend"(等待买家退货),
        // "waitsellerreceive"(等待卖家确认收货)
        if(!empty($param['refundStatus'])){
            $_param['refundStatus'] = $param['refundStatus'];
        }
        //买家memberId
        if(!empty($param['buyerMemberId'])){
            $_param['buyerMemberId'] = $param['buyerMemberId'];
        }
        //买家LoginId
        if(!empty($param['buyerLoginId'])){
            $_param['buyerLoginId'] = $param['buyerLoginId'];
        }
        //交易类型:
        // 担保交易(1),
        // 预存款交易(2),
        // ETC境外收单交易(3),
        // 即时到帐交易(4),
        // 保障金安全交易(5),
        // 统一交易流程(6),
        // 分阶段交易(7),
        // 货到付款交易(8),
        // 信用凭证支付交易(9),
        // 账期支付交易(10),
        // 1688交易4.0，
        //新分阶段交易(50060),
        // 当面付的交易流程(50070),
        // 服务类的交易流程(50080)
        if(!empty($param['tradeType'])){
            $_param['tradeType'] = $param['tradeType'];
        }
        //业务类型，支持： "cn"(普通订单类型), "ws"(大额批发订单类型), "yp"(普通拿样订单类型), "yf"(一分钱拿样订单类型), "fs"(倒批(限时折扣)订单类型), "cz"(加工定制订单类型), "ag"(协议采购订单类型), "hp"(伙拼订单类型), "gc"(国采订单类型), "supply"(供销订单类型), "nyg"(nyg订单类型), "factory"(淘工厂订单类型), "quick"(快订下单), "xiangpin"(享拼订单), "nest"(采购商城-鸟巢), "f2f"(当面付), "cyfw"(存样服务), "sp"(代销订单标记), "wg"(微供订单), "factorysamp"(淘工厂打样订单), "factorybig"(淘工厂大货订单)
        if(!empty($param['bizTypes'])){
            $_param['bizTypes'] = $param['bizTypes'];
        }
        //boolean,是否查询历史订单表,默认查询当前表
        if(!empty($param['isHis'])){
            $_param['isHis'] = $param['isHis'];
        }
        //商品名称
        if(!empty($param['productName'])){
            $_param['productName'] = $param['productName'];
        }
        //boolean,是否需要查询买家的详细地址信息和电话
        if(!empty($param['needBuyerAddressAndPhone'])){
            $_param['needBuyerAddressAndPhone'] = $param['needBuyerAddressAndPhone'];
        }
        //boolean,是否需要查询备注信息
        if(!empty($param['needMemoInfo'])){
            $_param['needMemoInfo'] = $param['needMemoInfo'];
        }
        //boolean,是否查找投诉中的地拟改单
        if(!empty($param['tousuStatus'])){
            $_param['tousuStatus'] = $param['tousuStatus'];
        }
        //买家评价状态 (4:已评价,5:未评价,6;不需要评价)
        if(!empty($param['buyerRateStatus'])){
            $_param['buyerRateStatus'] = $param['buyerRateStatus'];
        }
        //卖家评价状态 (4:已评价,5:未评价,6;不需要评价)
        if(!empty($param['sellerRateStatus'])){
            $_param['sellerRateStatus'] = $param['sellerRateStatus'];
        }
        //boolean,是否需要返回发货校验信息，对于打单发货场景必须要填，非常重要
        if(!empty($param['needCheckSend'])){
            $_param['needCheckSend'] = $param['needCheckSend'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 修改订单价格
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=cn.alibaba.open:trade.order.modifyOrderPrice-1&aopApiCategory=trade_new
     */
    public function modifyOrderPrice($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的订单id");
        }
        if(empty($param['carriage'])){
            return array_response([],1,"无效的订单修改之后的运费(单位为分)");
        }
        if(empty($param['entryDiscounts'])){
            return array_response([],1,"无效的改价明细(单位为分，正数为涨价，负数为减价)");
        }
        $name = $this->_version.'/cn.alibaba.open/trade.order.modifyOrderPrice';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'orderId'=>$param['orderId'],
            'carriage'=>$param['carriage'],
            'entryDiscounts'=>$param['entryDiscounts']//[{"id":111111, "discount":-200}, {"id":222222, "discount":-500}]
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 我的发货地址列表
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.logistics.mySendGoodsAddress.list.get-1&aopApiCategory=Logistics_NEW
     */
    public function mySendGoodsAddressList($shop_id = 0){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.logistics.mySendGoodsAddress.list.get';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>''
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 物流公司列表-所有的物流公司
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.logistics.OpQueryLogisticCompanyList.offline-1&aopApiCategory=Logistics_NEW
     */
    public function opQueryLogisticCompanyList($shop_id = 0){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.logistics.OpQueryLogisticCompanyList';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>''
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 物流公司列表-自联物流
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.logistics.OpQueryLogisticCompanyList.offline-1&aopApiCategory=Logistics_NEW
     */
    public function opQueryLogisticCompanyListOffline($shop_id = 0){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.logistics.OpQueryLogisticCompanyList.offline';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>''
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 根据地址解析地区码
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.addresscode.parse-1&aopApiCategory=trade_new
     */
    public function addresscode($shop_id = 0,$addressInfo = ''){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($addressInfo)){
            return array_response([],1,"无效的地址信息");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.addresscode.parse';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'addressInfo'=>$addressInfo
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 订单详情查看(卖家视角)
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.get.sellerView-1&aopApiCategory=trade_new
     */
    public function getSellerView($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的交易的订单id");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.get.sellerView';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
//            'webSite'=>$this->_web_site,
            'orderId'=>$param['orderId'],
        );
        if(!empty($param['includeFields'])){
            //查询结果中包含的域，
            //GuaranteesTerms：保障条款，
            //NativeLogistics：物流信息，
            //RateDetail：评价详情，
            //OrderInvoice：发票信息，
            //CanSendCheck：子订单是否可以发货。
            //默认返回GuaranteesTerms、NativeLogistics、OrderInvoice、CanSendCheck。
            $_param['includeFields'] = $param['includeFields'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 获取交易订单的物流信息(卖家视角)
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.trade.getLogisticsInfos.sellerView-1&aopApiCategory=Logistics_NEW
     */
    public function getLogisticsInfos($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的订单号");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.trade.getLogisticsInfos.sellerView';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'webSite'=>$this->_web_site,
            'orderId'=>$param['orderId']
        );
        if(!empty($param['fields'])){
            //需要返回的字段，目前有:company.name,sender,receiver,sendgood。返回的字段要用英文逗号分隔开
            $_param['fields'] = $param['fields'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 获取商品
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.product:alibaba.product.get-1&aopApiCategory=product_new
     */
    public function getProduct($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['productID'])){
            return array_response([],1,"无效的商品ID");
        }
        $name = $this->_version.'/com.alibaba.product/alibaba.product.get';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'productID'=>$param['productID']
        );
        if(!empty($param['webSite'])){
            //站点信息，指定调用的API是属于国际站（alibaba）还是1688网站（1688）
            $_param['webSite'] = $param['webSite'];
        }
        if(!empty($param['scene'])){
            //业务场景 零售通(lst) 1688市场(1688)
            $_param['scene'] = $param['scene'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 卖家查询商品列表
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.product:alibaba.product.list.get-1&aopApiCategory=product_new
     */
    public function productList($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        $name = $this->_version.'/com.alibaba.product/alibaba.product.list.get';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'pageNo'=>empty($param['pageNo'])?1:$param['pageNo'],
            'pageSize'=>empty($param['pageSize'])?20:$param['pageSize']
        );
        //业务标:['isMicroSupply']
        if(!empty($param['signs'])){
            $_param['signs'] = $param['signs'];
        }
        //商品状态，
        //published:上架状态，
        //expired：过期(包含手动过期与自动过期)，
        //TBD：to be delete，
        //deleted：删除，
        //new：新发，
        //modified：修改，
        //member expired：会员撤销
        if(!empty($param['statusList'])){
            $_param['statusList'] = $param['statusList'];
        }
        //类目
        if(!empty($param['categoryId'])){
            $_param['categoryId'] = $param['categoryId'];
        }
        //产品修改开始时间
        if(!empty($param['startModifyTime'])){
            $_param['startModifyTime'] = $param['startModifyTime'];
        }
        //产品修改结束时间
        if(!empty($param['endModifyTime'])){
            $_param['endModifyTime'] = $param['endModifyTime'];
        }
        //关键词
        if(!empty($param['subjectKey'])){
            $_param['subjectKey'] = $param['subjectKey'];
        }
        //货号
        if(!empty($param['cargoNumber'])){
            $_param['cargoNumber'] = $param['cargoNumber'];
        }
        //产品ID列表：[12323213,12312323]
        if(!empty($param['productIds'])){
            $_param['productIds'] = $param['productIds'];
        }
        //星级范围起始值0-5，不能高于endStar
        if(!empty($param['beginStar'])){
            $_param['beginStar'] = $param['beginStar'];
        }
        //星级范围起始值0-5，不能低于beginStar
        if(!empty($param['endStar'])){
            $_param['endStar'] = $param['endStar'];
        }
        //查询自定义分组ID，目前只支持查询一个
        if(!empty($param['groupIds'])){
            $_param['groupIds'] = $param['groupIds'];
        }
        //发布时间起始值
        if(!empty($param['startPublishTime'])){
            $_param['startPublishTime'] = $param['startPublishTime'];
        }
        //发布时间结束值
        if(!empty($param['endPublishTime'])){
            $_param['endPublishTime'] = $param['endPublishTime'];
        }
        //过期时间起始值
        if(!empty($param['startExpiredTime'])){
            $_param['startExpiredTime'] = $param['startExpiredTime'];
        }
        //过期时间结束值
        if(!empty($param['endExpiredTime'])){
            $_param['endExpiredTime'] = $param['endExpiredTime'];
        }
        //价格范围起始值
        if(!empty($param['priceStart'])){
            $_param['priceStart'] = $param['priceStart'];
        }
        //价格范围结束值
        if(!empty($param['priceEnd'])){
            $_param['priceEnd'] = $param['priceEnd'];
        }
        //排序条件：
        //CREATE_DATE,POST_DATE,MODIFY_DATE,APPROVED_DATE,EXPIRE_DATE,STATUS,ID,GROUP_ID,PRICE,SALE_QUANTITY
        if(!empty($param['orderByCondition'])){
            $_param['orderByCondition'] = $param['orderByCondition'];
        }
        //升序 ASC 还是降序 DESC
        if(!empty($param['orderByType'])){
            $_param['orderByType'] = $param['orderByType'];
        }
        //Boolean，支持在线交易
        if(!empty($param['supportOnlineTrade'])){
            $_param['supportOnlineTrade'] = $param['supportOnlineTrade'];
        }
        //Boolean，私密商品
        if(!empty($param['privateOffer'])){
            $_param['privateOffer'] = $param['privateOffer'];
        }
        //Boolean，是否需要详情
        if(!empty($param['needDetail'])){
            $_param['needDetail'] = $param['needDetail'];
        }
        //Boolean，是否需要运费
        if(!empty($param['needFreight'])){
            $_param['needFreight'] = $param['needFreight'];
        }
        //Boolean，是否需要自定义类目
        if(!empty($param['needUserCategoryInfo'])){
            $_param['needUserCategoryInfo'] = $param['needUserCategoryInfo'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 获取商品自定义分类信息
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=cn.alibaba.open:category.getSelfCatlist-1
     */
    public function getSelfCatlist($shop_id = 0,$memberId = ''){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($memberId)){
            return array_response([],1,"无效的会员ID");
        }
        $name = $this->_version.'/cn.alibaba.open/category.getSelfCatlist';
        $_param = array(
            '_aop_signature'=>'',
            'memberId'=>$memberId
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 取消交易
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.cancel-1&aopApiCategory=trade_new
     */
    public function cancelTrade($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['tradeID'])){
            return array_response([],1,"无效的交易id，订单号");
        }
        if(empty($param['cancelReason']) || !in_array($param['cancelReason'],['buyerCancel','sellerGoodsLack','other'])){
            return array_response([],1,"原因描述");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.cancel';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'webSite'=>$this->_web_site,
            'tradeID'=>$param['productID'],
            'cancelReason'=>$param['cancelReason']//原因描述；buyerCancel:买家取消订单;sellerGoodsLack:卖家库存不足;other:其它
        );
        if(!empty($param['remark'])){
            //备注
            $_param['remark'] = $param['remark'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 批量提交订单评价
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=cn.alibaba.open:trade.order.batch.rate-1&aopApiCategory=trade_new
     */
    public function orderBatchRate($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param) || !is_array($param)){
            return array_response([],1,"无效的订单评价");
        }
        //提交评价失败的订单Map(Long,String),前者为失败的订单号，后者为失败的错误码：
        // 1 返回为空时，创建全部成功
        // 2 没指定订单号及评价内容时,接口直接返回成功结果
        // 3 当订单已经评价过时，接口直接返回成功结果，不做任何处理
        // 4 当指定的订单不是指定postMemberId用户的订单是，接口直接返回成功结果，不做任何处理
        // 5 当指定的订单不处于待评价状态时，接口直接返回成功结果，不做任何处理
        /**
         * 请求参数json格式
        {                     // 批量提交评价的订单
            "92154312490525" : [ // 主订单1
            {
            "starLevel" : "1", // 星级
            "content" : "差评的" // 评价内容
            } ],
            "92154312590525" : [ // 主订单2
            {
            "starLevel" : "5", // 星级
            "content" : "好评的" // 评价内容
            } ]
        }
         */
        $name = $this->_version.'/cn.alibaba.open/trade.order.batch.rate';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'orders'=>$param,
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 修改订单备忘
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.order.memoAdd-1&aopApiCategory=trade_new
     */
    public function orderMemoAdd($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的订单ID");
        }
        if(empty($param['memo'])){
            return array_response([],1,"无效的备忘信息");
        }
        if(empty($param['remarkIcon'])){
            return array_response([],1,"无效的备忘图标");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.order.memoAdd';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'orderId'=>$param['orderId'],
            'memo'=>$param['memo'],
            'remarkIcon'=>$param['remarkIcon']//备忘图标，目前仅支持数字。1位红色图标，2为蓝色图标，3为绿色图标，4为黄色图标
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 退款单操作-卖家同意退货
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.refund.OpAgreeReturnGoods-1&aopApiCategory=trade_new
     */
    public function opAgreeReturnGoods($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['refundId'])){
            return array_response([],1,"无效的退款单Id");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.refund.OpAgreeReturnGoods';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'refundId'=>$param['refundId']
        );
        //卖家收货地址:浙江省杭州市滨江区XXXX
        if(!empty($param['address'])){
            $_param['address'] = $param['address'];
        }
        //邮编
        if(!empty($param['post'])){
            $_param['post'] = $param['post'];
        }
        //电话
        if(!empty($param['phone'])){
            $_param['phone'] = $param['phone'];
        }
        //全名
        if(!empty($param['fullName'])){
            $_param['fullName'] = $param['fullName'];
        }
        //手机
        if(!empty($param['mobilePhone'])){
            $_param['mobilePhone'] = $param['mobilePhone'];
        }
        //说明
        if(!empty($param['discription'])){
            $_param['discription'] = $param['discription'];
        }
        //1表示售中，2表示售后
        if(!empty($param['disputeType'])){
            $_param['disputeType'] = $param['disputeType'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 退款单操作记录列表
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.refund.OpQueryOrderRefundOperationList-1
     */
    public function opQueryOrderRefundOperationList($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['refundId'])){
            return array_response([],1,"无效的退款单Id");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.refund.OpQueryOrderRefundOperationList';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'refundId'=>$param['refundId'],//退款单Id
            'pageNo'=>empty($param['pageNo'])?1:$param['pageNo'],//当前页号
            'pageSize'=>empty($param['pageSize'])?100:$param['pageSize']//页大小
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 查询退款单详情-根据订单ID
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.refund.OpQueryBatchRefundByOrderIdAndStatus-1&aopApiCategory=trade_new
     */
    public function opQueryBatchRefundByOrderIdAndStatus($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的订单id");
        }
        if(empty($param['queryType']) || !in_array($param['queryType'],[1,3])){
            return array_response([],1,"无效的状态");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.refund.OpQueryBatchRefundByOrderIdAndStatus';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'orderId'=>$param['orderId'],//退款单Id
            'queryType'=>$param['queryType']//1：活动；3:退款成功（只支持退款中和退款成功）
        );
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 查询退款单列表(卖家视角)
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.refund.queryOrderRefundList-1&aopApiCategory=trade_new
     */
    public function queryOrderRefundList($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.refund.queryOrderRefundList';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'currentPageNum'=>empty($param['currentPageNum'])?0:$param['currentPageNum'],
            'pageSize'=>empty($param['pageSize'])?10:$param['pageSize']
        );
        //订单Id
        if(!empty($param['orderId'])){
            $_param['orderId'] = $param['orderId'];
        }
        //退款申请时间（起始）
        if(!empty($param['applyStartTime'])){
            $_param['applyStartTime'] = $param['applyStartTime'];
        }
        //退款申请时间(截止)
        if(!empty($param['applyEndTime'])){
            $_param['applyEndTime'] = $param['applyEndTime'];
        }
        //退款状态列表
        //等待卖家同意 waitselleragree;
        //退款成功 refundsuccess;
        //退款关闭 refundclose;
        //待买家修改 waitbuyermodify;
        //等待买家退货 waitbuyersend;
        //等待卖家确认收货 waitsellerreceive
        if(!empty($param['applyEndTime'])){
            $_param['applyEndTime'] = $param['applyEndTime'];
        }
        //买家memberId
        if(!empty($param['buyerMemberId'])){
            $_param['buyerMemberId'] = $param['buyerMemberId'];
        }
        //买家loginId
        if(!empty($param['buyerLoginId'])){
            $_param['buyerLoginId'] = $param['buyerLoginId'];
        }
        //退货运单号
        if(!empty($param['logisticsNo'])){
            $_param['logisticsNo'] = $param['logisticsNo'];
        }
        //退款修改时间(起始)
        if(!empty($param['modifyStartTime'])){
            $_param['modifyStartTime'] = $param['modifyStartTime'];
        }
        //退款修改时间(截止)
        if(!empty($param['modifyEndTime'])){
            $_param['modifyEndTime'] = $param['modifyEndTime'];
        }
        //1:售中退款，2:售后退款；0:所有退款单
        if(!empty($param['dipsuteType'])){
            $_param['dipsuteType'] = $param['dipsuteType'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 查询退款单详情-根据退款单ID
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.refund.OpQueryOrderRefund-1&aopApiCategory=trade_new
     */
    public function opQueryOrderRefund($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['refundId'])){
            return array_response([],1,"无效的退款单Id");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.refund.OpQueryOrderRefund';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'refundId'=>$param['refundId']//退款单业务主键 TQ+ID
        );
        //boolean,需要退款单的超时信息
        if(!empty($param['needTimeOutInfo'])){
            $_param['needTimeOutInfo'] = $param['needTimeOutInfo'];
        }
        //boolean,需要退款单伴随的所有退款操作信息
        if(!empty($param['needOrderRefundOperation'])){
            $_param['needOrderRefundOperation'] = $param['needOrderRefundOperation'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 延迟订单确认时间(卖家操作)
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.trade:alibaba.trade.order.PostponeConfirmTime-1&aopApiCategory=trade_new
     */
    public function postponeConfirmTime($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的订单ID");
        }
        if(empty($param['delayedDays'])){
            return array_response([],1,"无效的延迟时间");
        }
        $name = $this->_version.'/com.alibaba.trade/alibaba.trade.order.PostponeConfirmTime';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'orderId'=>$param['orderId'],//订单ID
            'delayedDays'=>$param['delayedDays']//延迟时间（天）
        );
        //子支付单号，如果传递，该值必须是真实的subPayOrderId
        if(!empty($param['subPayOrderId'])){
            $_param['subPayOrderId'] = $param['subPayOrderId'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 物流发货-无需物流
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.logistics.OpDeliverySendOrder.dummy-1&aopApiCategory=Logistics_NEW
     */
    public function opDeliverySendOrderDummy($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['sendGoods'])){
            return array_response([],1,"无效的发货对象列表");
        }
        if(empty($param['extBody'])){
            return array_response([],1,"无效的订单数据");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.logistics.OpDeliverySendOrder.dummy';
        //JSON字符串,
        //extBodyJson中的noLogisticsCondition必填，取值字符串1到5：
        //“1”：其他第三方物流、小型物充商、车队等（noLogisticsName、noLogisticsTel必填）；
        //“2”：补运费、差价（noLogisticsBillNo必填）；
        //“3”：卖家配送（noLogisticsName、noLogisticsTel必填）；
        //“4”：买家自提；“5”：其他原因（remarks必填）。
        //其他字段根据noLogisticsCondition的值不同，必填要求不同。
        //字段说明：
        //无需物流原因:noLogisticsCondition;
        //无需物流名称:noLogisticsName;
        //无需物流电话:noLogisticsTel;
        //无需物流单号，不同的无需物流原因，该字段解释不同:noLogisticsBillNo。
        //{"noLogisticsBillNo":"111111111111111111","noLogisticsCondition":"3","noLogisticsName":"张三","noLogisticsTel":"13999999999"}
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'sendGoods'=>$param['sendGoods'],
            'extBody'=>$param['extBody']
        );
        //备注
        if(!empty($param['remarks'])){
            $_param['remarks'] = $param['remarks'];
        }
        //发货时间：标准时间格式：yyyyMMddHHmmssSSSZ，例如：20120801154220368+0800
        if(!empty($param['gmtSend'])){
            $_param['gmtSend'] = $param['gmtSend'];
        }
        //详见接口文档
        if(!empty($param['extParam'])){
            $_param['extParam'] = $param['extParam'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 物流发货-自己联系物流发货
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.logistics.OpDeliverySendOrder.offline-1&aopApiCategory=Logistics_NEW
     */
    public function opDeliverySendOrderOffline($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['sendGoods'])){
            return array_response([],1,"无效的发货对象列表");
        }
        if(empty($param['extBody'])){
            return array_response([],1,"无效的订单数据");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.logistics.OpDeliverySendOrder.offline';
        //JSON字符串，
        //cpCode 为物流公司code，对应物流公司信息获取接口的companyNo（非数字Id）;
        // logisticsCpName:物流公司名称，对应物流公司信息获取接口的companyName；
        // mailNo：运单号； 可以通过获取 "物流公司列表-自联物流" 接口查询到数据。
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'sendGoods'=>$param['sendGoods'],
            'extBody'=>$param['extBody']
        );
        //备注
        if(!empty($param['remarks'])){
            $_param['remarks'] = $param['remarks'];
        }
        //发货时间：标准时间格式：yyyyMMddHHmmssSSSZ，例如：20120801154220368+0800
        if(!empty($param['gmtSend'])){
            $_param['gmtSend'] = $param['gmtSend'];
        }
        //详见接口文档
        if(!empty($param['extParam'])){
            $_param['extParam'] = $param['extParam'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo 获取交易订单的物流跟踪信息(卖家视角)
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?id=com.alibaba.logistics:alibaba.trade.getLogisticsTraceInfo.sellerView-1&aopApiCategory=Logistics_NEW
     */
    public function getLogisticsTraceInfo($shop_id = 0,$param = []){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        if(empty($param['orderId'])){
            return array_response([],1,"无效的订单号");
        }
        $name = $this->_version.'/com.alibaba.logistics/alibaba.trade.getLogisticsTraceInfo.sellerView';
        $_param = array(
            '_aop_signature'=>'',
            'access_token'=>'',
            'orderId'=>$param['orderId'],
            'webSite'=>$this->_web_site
        );
        //该订单下的物流编号
        if(!empty($param['logisticsId'])){
            $_param['logisticsId'] = $param['logisticsId'];
        }
        $res = $this->api($name,$_param,$shop_id);
        return $res;
    }

    /**
     * @todo app 在服务市场被订购的订单列表
     * @author ZJF
     * https://open.1688.com/api/apidocdetail.htm?aopApiCategory=service_platform&id=cn.alibaba.open%3Aapp.order.get-1
     */
    public function getAppOrder($param = []){
        $name = $this->_version.'/cn.alibaba.open/app.order.get';
        $_param = array(
            '_aop_signature'=>'',
            'gmtCreate'=>date('YmdHis')."0+0800",
            'pageSize'=>50,
            'startIndex'=>empty($param['startIndex'])?1:$param['startIndex']
        );
        //订购者会员memberId
        if(!empty($param['memberId'])){
            $_param['memberId'] = $param['memberId'];
        }
        if(!empty($param['bizStatusList'])){
            $_param['bizStatusList'] = $param['bizStatusList'];
        }
        if(!empty($param['loginId'])){
            $_param['loginId'] = $param['loginId'];
        }
        $res = $this->api($name,$_param,0);
        return $res;
    }

    /**
     * @todo 对外返回签名完的数据
     * @author ZJF
     * @param string $name
     * @param array $param
     * @param int $shop_id
     * @param string $method
     * @return array
     */
    public function pub_api($name='',$param=[],$shop_id = 0,$method = 'POST'){
        $request_data = $this->api($name,$param,$shop_id,$method,1);
        return $request_data;
    }

    /**
     * @todo 取accessToken
     * @author ZJF
     */
    private function getAccessToken($shop_id = 0){
        if(empty($shop_id) || !is_numeric($shop_id)){
            return array_response([],1,"无效的店铺ID");
        }
        //先从session中获取
        //取数据
        $shop_model = new Shop();
        $session_shop = session("shop_{$shop_id}");
        if(empty($session_shop) || time() > $session_shop['session_expires_time']) {
            //session不存在，或，已过期
            //实时查询
            $shop_info = $shop_model->where("id='{$shop_id}'")->find();
            if(empty($shop_info)){
                return array_response([],1,"无授权信息");
            }
            //设置过期时间15分钟
            $shop_info['session_expires_time'] = bcadd(time(),900);
            $shop_info = ObjectToArray($shop_info);
            //存session
            session("shop_{$shop_id}",$shop_info);
        }
        else{
            $shop_info = $session_shop;
        }
        //access_token判断是否过期
        if(time() > $shop_info['expires_timeout'] && time() > $shop_info['refresh_token_timeout']){
            //access_token过期，refresh_token过期
            //重新授权
            return array_response(array('url'=>$this->createAuthUrl()),10019);
        }
        //access_token过期，refresh_token未过期
        if(time() > $shop_info['expires_timeout'] && $shop_info['refresh_token_timeout'] > time()){
            //刷新token
            $ref_res = $this->refreshAccessToken($shop_info['refresh_token']);
            if($ref_res['code']!=0){
                //刷新失败，需要重新授权
                return array_response(array('url'=>$this->createAuthUrl()),10019);
            }
            $access_timeout = bcadd(time(),bcsub($ref_res['data']['expires_in'],60));
            //刷新成功，更新数据库，及session中数据
            $shop_res = $shop_model->where("id='{$shop_id}'")->save(array(
                'access_token'=>$ref_res['data']['access_token'],
                'expires_timeout'=>$access_timeout,
                'mtime'=>date('Y-m-d H:i:s')
            ));
            //存session
            $shop_info['access_token'] = $ref_res['data']['access_token'];
            $shop_info['expires_timeout'] = $access_timeout;
            $shop_info['session_expires_time'] = empty($shop_info['session_expires_time'])?bcadd(time(),900):$shop_info['session_expires_time'];
            session("shop_{$shop_id}",$shop_info);
        }
        return array_response($shop_info);
    }

    /**
     * @todo 公共请求
     * @author ZJF
     */
    private function api($name='',$param=[],$shop_id = 0,$method = 'POST',$request = 0){
        //测试用
        $s = 'param2'.'/'.$name.'/'.$this->_app_key;
        $url = $this->_site_url."/{$s}";
        $_param = array(
            'name'=>$name,
            'param'=>$param,
            'shop_id'=>$shop_id,
            'method'=>$method
        );
        $response = HttpRequest('https://quickprint.xingyebao.com/callback/proxyRequest',[],json_encode($_param),'POST');
        $response = json_decode($response,true);
        if($response['code'] == 0){
            //成功
            if($method == 'GET'){
                $response = HttpRequest($url,$response['data']);
            }else{
                $response = HttpRequest($url,[],$response['data'],'POST');
                //print_data($response);
            }
            //处理错误返回信息
            $check = json_decode($response, true, 512, JSON_BIGINT_AS_STRING);
            if(is_null($check)) {
                $response = preg_replace('/[\x00-\x08\x10\x0B\x0C\x0E-\x19\x7F]' .
                    '|[\x00-\x7F][\x80-\xBF]+' .
                    '|([\xC0\xC1]|[\xF0-\xFF])[\x80-\xBF]*' .
                    '|[\xC2-\xDF]((?![\x80-\xBF])|[\x80-\xBF]{2,})' .
                    '|[\xE0-\xEF](([\x80-\xBF](?![\x80-\xBF]))|(?![\x80-\xBF]{2})|[\x80-\xBF]{3,})/S',
                    '?', $response);
                $response = preg_replace('/\xE0[\x80-\x9F][\x80-\xBF]' .
                    '|\xED[\xA0-\xBF][\x80-\xBF]/S', '?', $response);
                $response = json_decode($response, true, 512, JSON_BIGINT_AS_STRING);
            }else{
                $response = $check;
            }
            //返回错误信息
            if(!empty($response['error_code'])){
                return array_response($response,$response['error_code'],$response['error_message']);
            }
            else if(isset($response['errorCode'])){
                if(empty($response['errorMessage'])){
                    $msg = json_decode($response['errorMsg'],true);
                    if(isset($msg['errorMessage'])){
                        $response['errorMessage'] = $msg['errorMessage'];
                    }else{
                        $response['errorMessage'] = $response['errorMsg'];
                    }
                }
                return array_response($response,$response['errorCode'],$response['errorMessage']);
            }
            else if(isset($response['msgCode'])){
                return array_response($response,$response['msgCode'],$response['msgInfo']);
            }
            //成功
            return array_response($response);
        }
        return array_response([],1,'获取签名数据失败');
        //以上为测试用
    }

    /**
     * @todo 生成签名
     * @author ZJF
     * https://open.1688.com/api/apidoclist.htm?id=624397
     */
    private function createSign($param, $s = ''){
        ksort($param);
        $factor = '';
        foreach ($param as $k=>$v){
            $factor .= $k.$v;
        }
        return strtoupper(bin2hex(hash_hmac("sha1", $s.$factor, $this->_app_secret, true)));
    }
}